package com.easy.cloud.web.service.upms.biz.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.easy.cloud.web.component.core.constants.GlobalCommonConstants;
import com.easy.cloud.web.component.core.enums.StatusEnum;
import com.easy.cloud.web.component.core.exception.BusinessException;
import com.easy.cloud.web.component.core.tenant.TenantBroker;
import com.easy.cloud.web.component.core.util.BeanUtils;
import com.easy.cloud.web.component.mysql.query.SpecificationWrapper;
import com.easy.cloud.web.service.upms.api.dto.TenantDTO;
import com.easy.cloud.web.service.upms.api.dto.TenantQueryDTO;
import com.easy.cloud.web.service.upms.api.vo.TenantVO;
import com.easy.cloud.web.service.upms.biz.constant.UpmsConstants;
import com.easy.cloud.web.service.upms.biz.converter.TenantConverter;
import com.easy.cloud.web.service.upms.biz.domain.DeptDO;
import com.easy.cloud.web.service.upms.biz.domain.RoleDO;
import com.easy.cloud.web.service.upms.biz.domain.TenantDO;
import com.easy.cloud.web.service.upms.biz.domain.UserDO;
import com.easy.cloud.web.service.upms.biz.repository.DeptRepository;
import com.easy.cloud.web.service.upms.biz.repository.RoleRepository;
import com.easy.cloud.web.service.upms.biz.repository.TenantRepository;
import com.easy.cloud.web.service.upms.biz.repository.UserRepository;
import com.easy.cloud.web.service.upms.biz.service.ITenantService;
import com.easy.cloud.web.service.upms.biz.service.IUserService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.util.List;
import java.util.Objects;

/**
 * Tenant 业务逻辑（平台）
 *
 * @author Fast Java
 * @date 2023-08-03 15:00:02
 */
@Slf4j
@Service
@AllArgsConstructor
public class TenantServiceImpl implements ITenantService {

    private final TenantRepository tenantRepository;

    private final UserRepository userRepository;

    private final RoleRepository roleRepository;

    private final DeptRepository deptRepository;

    private final PasswordEncoder passwordEncoder;

    private final IUserService userService;

    @Override
    @Transactional(rollbackOn = Exception.class)
    public void init() {
        // 未初始化过数据
        if (tenantRepository.count() <= 0) {
            // 创建租户
            TenantDTO tenantDTO = this.initJsonToBean("json/sys_tenant.json", TenantDTO.class);
            // 设置开始时间为今天的凌晨
            tenantDTO.setStartDate(DateUtil.beginOfDay(DateUtil.date()));
            // 当前租户的使用日期为此时到99年的现在
            tenantDTO.setEndDate(DateUtil.endOfDay(DateUtil.offsetMonth(DateUtil.date(), 99 * 12)));
            // 存储超级管理员信息
            TenantVO tenantVO = this.save(tenantDTO);
            // 切换租户信息
            TenantBroker.runAs(tenantVO.getId(), tenantId -> {
                // 初始化角色数据
                List<RoleDO> roles = this.initJsonToList("json/sys_role.json", RoleDO.class);
                // 初始化存储
                roleRepository.saveAll(roles);

                // 创建超管
                UserDO admin = this.initJsonToBean("json/sys_user.json", UserDO.class);
                // 绑定超管角色
                roles.stream().filter(roleDO -> roleDO.getCode().equals(GlobalCommonConstants.SUPER_ADMIN_ROLE))
                        .findFirst().ifPresent(roleDO -> admin.setRoles(CollUtil.newArrayList(roleDO)));
                // 编译密码
                admin.setPassword(passwordEncoder.encode(admin.getPassword()));
                // 存储超级管理员信息
                userRepository.save(admin);
                log.info("init platform content success!");
            });
        }
    }

    /**
     * 初始化租户信息
     *
     * @param tenant 租户信息
     */
    private void initTenantInfo(TenantDO tenant) {
        // 切换租户信息
        TenantBroker.runAs(tenant.getId(), tenantId -> {
            // 初始化租户账户信息
            UserDO user = UserDO.builder()
                    .nickName(tenant.getName())
                    .userName(tenant.getName())
                    // TODO 创建租户，使用默认密码，或使用短信通知等模式
                    .password(passwordEncoder.encode(UpmsConstants.DEFAULT_PASSWORD))
                    .build();

            // 1、初始化租户的部门信息
            DeptDO dept = tenant.convertTo(DeptDO.class);
            dept.setId(null);
            deptRepository.save(dept);
            user.setDept(dept);

            // 2、绑定角色信息
            roleRepository.findFirstByCode(GlobalCommonConstants.TENANT_ROLE)
                    .ifPresent(roleDO -> user.setRoles(CollUtil.newArrayList(roleDO)));

            // 保存用户信息
            userRepository.save(user);
        });
    }

    @Override
    @Transactional(rollbackOn = Exception.class)
    public TenantVO save(TenantDTO tenantDTO) {
        // 转换成DO对象
        TenantDO tenant = TenantConverter.convertTo(tenantDTO);
        // 校验租户是否存在
        if (tenantRepository.existsByName(tenantDTO.getName())) {
            throw new BusinessException("当前租户信息已存在");
        }

        // 存储
        tenantRepository.save(tenant);
        // 初始化租户信息
        this.initTenantInfo(tenant);
        // 转换对象
        return TenantConverter.convertTo(tenant);
    }

    @Override
    @Transactional(rollbackOn = Exception.class)
    public TenantVO update(TenantDTO tenantDTO) {
        // 更新操作，ID不能为空
        if (Objects.isNull(tenantDTO.getId())) {
            throw new RuntimeException("当前更新对象ID为空");
        }

        // 获取当前部门信息
        TenantDO tenant = tenantRepository.findById(tenantDTO.getId())
                .orElseThrow(() -> new BusinessException("当前租户信息不存在"));
        // 将修改的数据赋值给数据库数据
        BeanUtils.copyProperties(tenantDTO, tenant, true);
        // 存储，更新租户信息不修改部门、用户等信息
        tenantRepository.save(tenant);
        // 转换对象
        return TenantConverter.convertTo(tenant);
    }

    @Override
    @Transactional(rollbackOn = Exception.class)
    public Boolean removeById(String tenantId) {
        // TODO 业务逻辑校验

        // 逻辑删除
        tenantRepository.logicDelete(tenantId);
        // 移除租户下的所有用户
        userService.removeTenantAllUser(tenantId);
        return true;
    }

    @Override
    @Transactional(rollbackOn = Exception.class)
    public TenantVO freezeTenant(String tenantId) {
        // TODO 业务逻辑校验
        TenantDO tenantDO = tenantRepository.findById(tenantId)
                .orElseThrow(() -> new BusinessException("当前租户信息不存在"));
        // 删除
        tenantRepository.updateTenantStatus(tenantId, StatusEnum.FREEZE_STATUS);
        // 移除租户下的所有用户
        userService.freezeTenantAllUser(tenantId);
        return TenantConverter.convertTo(tenantDO);
    }

    @Override
    public TenantVO detailById(String tenantId) {
        // TODO 业务逻辑校验

        // 删除
        TenantDO tenant = tenantRepository.findById(tenantId)
                .orElseThrow(() -> new RuntimeException("当前数据不存在"));
        // 转换对象
        return TenantConverter.convertTo(tenant);
    }

    @Override
    public List<TenantVO> list(TenantQueryDTO tenantQueryDTO) {
        return TenantConverter.convertTo(tenantRepository.findAll(SpecificationWrapper.where()
                .like(StrUtil.isNotBlank(tenantQueryDTO.getName()), TenantDO::getName, tenantQueryDTO.getName())
                .eq(Objects.nonNull(tenantQueryDTO.getType()), TenantDO::getType, tenantQueryDTO.getType())
                .eq(Objects.nonNull(tenantQueryDTO.getProvince()), TenantDO::getProvince, tenantQueryDTO.getProvince())
                .eq(Objects.nonNull(tenantQueryDTO.getCity()), TenantDO::getCity, tenantQueryDTO.getCity())
                .eq(Objects.nonNull(tenantQueryDTO.getDistrict()), TenantDO::getDistrict, tenantQueryDTO.getDistrict())
                .eq(Objects.nonNull(tenantQueryDTO.getStreet()), TenantDO::getStreet, tenantQueryDTO.getStreet())
                .gte(Objects.nonNull(tenantQueryDTO.getStartDate()), TenantDO::getStartDate, tenantQueryDTO.getStartDate())
                .lte(Objects.nonNull(tenantQueryDTO.getEndDate()), TenantDO::getEndDate, tenantQueryDTO.getEndDate())
        ));
    }

    @Override
    public Page<TenantVO> page(TenantQueryDTO tenantQueryDTO) {
        // 构建分页数据
        return TenantConverter.convertTo(tenantRepository.findAll(SpecificationWrapper.where()
                .like(StrUtil.isNotBlank(tenantQueryDTO.getName()), TenantDO::getName, tenantQueryDTO.getName())
                .eq(Objects.nonNull(tenantQueryDTO.getType()), TenantDO::getType, tenantQueryDTO.getType())
                .eq(Objects.nonNull(tenantQueryDTO.getProvince()), TenantDO::getProvince, tenantQueryDTO.getProvince())
                .eq(Objects.nonNull(tenantQueryDTO.getCity()), TenantDO::getCity, tenantQueryDTO.getCity())
                .eq(Objects.nonNull(tenantQueryDTO.getDistrict()), TenantDO::getDistrict, tenantQueryDTO.getDistrict())
                .eq(Objects.nonNull(tenantQueryDTO.getStreet()), TenantDO::getStreet, tenantQueryDTO.getStreet())
                .gte(Objects.nonNull(tenantQueryDTO.getStartDate()), TenantDO::getStartDate, tenantQueryDTO.getStartDate())
                .lte(Objects.nonNull(tenantQueryDTO.getEndDate()), TenantDO::getEndDate, tenantQueryDTO.getEndDate()), tenantQueryDTO.pageable()));
    }
}